<?php

class Node {
	private $value;
	private $height;
	private $minGap;
	private $leftChild;
	private $rightChild;
	
	public function __construct($value = null) {
		$this->value = $value;
		$this->height = 0;
		$this->minGap = 999999;	// or infinity
		$this->parent = null;
		$this->leftChild = null;
		$this->rightChild = null;
	}

	public function getParent() {

		return $this->parent;
	}
	
	public function getLeftChild() {
		
		return $this->leftChild;
	}
		
	public function getRightChild() {
		
		return $this->rightChild;
	}

	
	public function getHeight() {

		return $this->height;
	}	
	
	public function getValue() {
		
		return $this->value;
	}
	
	public function getMinGap() {
		
		return $this->minGap;
	}

	public function getBalance() {
		$balance = 0;
		if ($this->getLeftChild() != null && $this->getRightChild() != null) {
			$balance = $this->getRightChild()->getHeight() - $this->getLeftChild()->getHeight();
		} else if ($this->getLeftChild() != null) {
			$balance = (-1) * $this->getLeftChild()->getHeight() + 1;
		} else if ($this->getRightChild() != null) {
			$balance = $this->getRightChild()->getHeight() + 1;
		}

		return $balance;
	}


	public function setParent(Node $node = null) {
		$this->parent = $node;
	}

	public function setLeftChild(Node $node = null) {
		if ($node != null) {
			$node->setParent($this);
		}
		
		$this->leftChild = $node;
		$this->updateHeight();
		$this->calculateMinGap();

		return $this->leftChild;
	}

	public function setRightChild(Node $node = null) {
		if ($node != null) {
			$node->setParent($this);
		}
		$this->rightChild = $node;
		$this->updateHeight();
		$this->calculateMinGap();

		return $this->rightChild;
	}

	public function setHeight($height) {
		$this->height = (int)$height;
	}

	public function setValue($value) {
		$this->value = $value;
	}

	public function updateHeight() {
		if ($this->leftChild != null && $this->rightChild != null) {
			if ($this->leftChild->getHeight() > $this->rightChild->getHeight()) {
				$this->height = $this->leftChild->getHeight() + 1;
			} else {
				$this->height = $this->rightChild->getHeight() + 1;
			}
		} else if ($this->leftChild != null) {
			$this->height = $this->leftChild->getHeight() + 1;
		} else if ($this->rightChild != null) {
			$this->height = $this->rightChild->getHeight() + 1;
		} else {
			$this->height = 0;
		}

		return $this->height;
	}
	
	public function calculateMinGap() {
		if ($this->leftChild != null && $this->rightChild != null) {
			$leftMinGap = $this->value - $this->leftChild->getValue();
			$rightMinGap = $this->rightChild->getValue() - $this->value;
			$leftChildMinGap = $this->leftChild->getMinGap();
			$rightChildMinGap = $this->rightChild->getMinGap();
			$this->minGap = min(array($leftMinGap, $rightMinGap, $leftChildMinGap, $rightChildMinGap));
		} else if ($this->leftChild != null) {
			$leftMinGap = $this->value - $this->leftChild->getValue();
			$leftChildMinGap = $this->leftChild->getMinGap();
			$this->minGap = min(array($leftMinGap, $leftChildMinGap));
		} else if ($this->rightChild != null) {
			$rightMinGap =$this->rightChild->getValue() - $this->value;
			$rightChildMinGap = $this->rightChild->getMinGap();
			$this->minGap = min(array($rightMinGap, $rightChildMinGap));
		}
	}

	public function __toString() {

		return (string)$this->value;
	}
}